using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Vj.ParticlesLibrary;
using Vj.MathLibrary;
using Tao.OpenGl;
using Vj.ShapeLibrary;

namespace Vj.ParticlesApp
{
    public partial class Shell : Form
    {
        //private FountainEmitter emitter;
        private FireworkEmitter emitter;

        private Vector globalTranslation;
        private Vector globalRotation;
        private double globalRotationAngle;
        private Vector globalScale;

        public Shell()
        {
            InitializeComponent();

            ParticleEnvironment.Instance.Gravity = new Vector(0.0, -0.05, 0.0);
            ParticleEnvironment.Instance.Wind = new Vector(0.0, 0.0, 0.0);
        }

        #region Initialization

        private void simpleOpenGlControl1_Load(object sender, EventArgs e)
        {
            simpleOpenGlControl1.InitializeContexts();
            simpleOpenGlControl1.AutoSwapBuffers = true;

            globalTranslation = new Vector(0.0, 0.0, 0.0);
            globalRotation = new Vector(0.0, 0.0, 0.0);
            globalScale = new Vector(1.0, 1.0, 1.0);
            globalRotationAngle = 0.0f;

            InitGL();
            SetLights();

            simpleOpenGlControl1_Resize(null, null);
        }

        private static bool InitGL()
        {
            //Gl.glShadeModel(Gl.GL_SMOOTH);
            Gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
            Gl.glClearDepth(1);
            Gl.glEnable(Gl.GL_DEPTH_TEST);
            Gl.glDepthFunc(Gl.GL_LEQUAL);
            Gl.glHint(Gl.GL_PERSPECTIVE_CORRECTION_HINT, Gl.GL_NICEST);
            Gl.glEnable(Gl.GL_LIGHT0);
            Gl.glEnable(Gl.GL_LIGHT1);
            Gl.glEnable(Gl.GL_LIGHTING);
            Gl.glEnable(Gl.GL_NORMALIZE);

            return true;
        }

        private void SetLights()
        {
            // global light
            float[] global_ambient = { 0.75f, 0.75f, 0.75f, 1.0f };
            Gl.glLightModelfv(Gl.GL_LIGHT_MODEL_AMBIENT, global_ambient);

            float[] light_ambient = { 0.4f, 0.4f, 0.4f, 1.0f };
            float[] light_diffuse = { 0.6f, 0.6f, 0.6f, 1.0f };
            float[] light_specular = { 0.6f, 0.6f, 0.6f, 1.0f };
            
            float[] light_position0 = { -50.0f, 20.0f, 10.0f, 1.0f };
            float[] light_position1 = { 50.1f, 20.0f, 10.0f, 1.0f };

            Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_POSITION, light_position0);
            Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_SPECULAR, light_specular);
            Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_AMBIENT, light_ambient);
            Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_DIFFUSE, light_diffuse);

            Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_POSITION, light_position1);
            Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_SPECULAR, light_specular);
            Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_AMBIENT, light_ambient);
            Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_DIFFUSE, light_diffuse);
        }

        private void simpleOpenGlControl1_Resize(object sender, EventArgs e)
        {
            int w = simpleOpenGlControl1.Width;
            int h = simpleOpenGlControl1.Height;

            float ratio = ((float)w / (float)h);

            // set viewport to current window size
            Gl.glViewport(0, 0, w, h);

            // set up prespective projection
            Gl.glMatrixMode(Gl.GL_PROJECTION);
            Gl.glLoadIdentity();
            Glu.gluPerspective(45, ratio, 1, 50);

            // set up model view matrix
            Gl.glMatrixMode(Gl.GL_MODELVIEW);
            Gl.glLoadIdentity();
        }

        #endregion

        private void simpleOpenGlControl1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
        {
            Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);
            Gl.glLoadIdentity();

            Gl.glTranslated(0.0, 0.0, -30.0);
            //Gl.glTranslated(globalTranslation.X, globalTranslation.Y, globalTranslation.Z);
            //Gl.glRotated(globalRotationAngle, globalRotation.X, globalRotation.Y, globalRotation.Z);
            //Gl.glScaled(globalScale.X, globalScale.Y, globalScale.Z);

            if (emitter != null)
            {
                emitter.Update();
                emitter.Draw();
            }
            

            //globalRotationAngle++;
            //if (globalRotationAngle > 360)
            //    globalRotationAngle = 0;
        }

        private int currentIter = 0;
        private DateTime startTime;

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (currentIter == 10)
            {
                TimeSpan diff = DateTime.Now.Subtract(startTime);
                timespanTextBox.Text = string.Format("{0}m : {1}s : {2}ms",
                    diff.Minutes.ToString(), diff.Seconds.ToString(),
                    diff.Milliseconds.ToString());
            }

            currentIter++;
            //emitter.Update();
            simpleOpenGlControl1.Refresh();
        }



        private void startButton_Click(object sender, EventArgs e)
        {
            currentIter = 0;
            startTime = DateTime.Now;

            //emitter = new FountainEmitter(new Vector(0.0, -1.0, 0.0));
            emitter = new FireworkEmitter(new Vector(0.0, -1.0, 0.0));
            timer1.Start();
            //simpleOpenGlControl1.Refresh();

        }

        private void stopButton_Click(object sender, EventArgs e)
        {
            timer1.Stop();
        }

        #region View Handlers
        private void scaleScrollBar_Scroll(object sender, ScrollEventArgs e)
        {
            // [0, 2]
            globalScale.X = (double)(2*scaleScrollBar.Value / 100);
            globalScale.Y = (double)(2 * scaleScrollBar.Value / 100);
            globalScale.Z = (double)(2 * scaleScrollBar.Value / 100);
            
            simpleOpenGlControl1.Refresh();
        }

        private void xTransScrollBar_Scroll(object sender, ScrollEventArgs e)
        {
            // [-5.0, 5.0]
            globalTranslation.X = 10 * (xTransScrollBar.Value / 100) - 5;
            simpleOpenGlControl1.Refresh();
        }

        private void yTransScrollBar_Scroll(object sender, ScrollEventArgs e)
        {
            // [-5.0, 5.0]
            globalTranslation.Y = 10 * (yTransScrollBar.Value / 100) - 5;
            simpleOpenGlControl1.Refresh();
        }

        private void zTransScrollBar_Scroll(object sender, ScrollEventArgs e)
        {
            // [-5.0, 5.0]
            globalTranslation.Z = 10 * (zTransScrollBar.Value / 100) - 5;
            simpleOpenGlControl1.Refresh();
        }

        private void xRotScrollBar_Scroll(object sender, ScrollEventArgs e)
        {
            globalRotation.X = xRotScrollBar.Value/100;
            simpleOpenGlControl1.Refresh();
        }

        private void yRotScrollBar_Scroll(object sender, ScrollEventArgs e)
        {
            globalRotation.Y = yRotScrollBar.Value / 100;
            simpleOpenGlControl1.Refresh();
        }

        private void zRotScrollBar_Scroll(object sender, ScrollEventArgs e)
        {
            globalRotation.Z = zRotScrollBar.Value / 100;
            simpleOpenGlControl1.Refresh();
        }

        #endregion

    }
}